package com.caac.core.config;

import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletContext;

import com.caac.core.dao.BaseDao;
import com.caac.core.util.ListMapClass;
import org.apache.commons.digester.Digester;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import com.ac.app.dm.PickSubject;
import com.caac.core.service.UserManager;
import com.caac.core.dao.UserDao;
import com.caac.core.dm.Permission;
import com.caac.core.dm.Role;

/**
 * <p>Title: </p>
 * <p>Description: </p>
 * <p>Copyright: Copyright Intolong 2004</p>
 * <p>Company: Intolong</p>
 * @author <a href="mailto:intolong@163.com">Intolong</a>
 * @version 1.0
 */

public class Config implements Serializable {
    private static final Log LOG = LogFactory.getLog(Config.class);
    private static Config instance = new Config();
    private static WebApplicationContext ctx;
    private Map operators = new HashMap();
    private Map labels = new HashMap();
    private Map queries = new HashMap();
    private Map orders = new HashMap();
    private Map views = new HashMap();
    
    private ListMapClass rolePermissions;
    private List roles;
    private ListMapClass subjects;

    private Date startupTime;
    private String realPath;

    public static Config getInstance() {
        return instance;
    }

    private Config() {
    }

    public Operator getOperator(String key) {
        Operator result = (Operator) operators.get(key);
        if (result == null) {
            throw new NullPointerException("Operator '" + key + "' not found");
        }
        return result;
    }

    public void addOperator(Operator operator) {
        operators.put(operator.getName(), operator);
    }
    
    public LabelClass getLabel(String key) {
        LabelClass result = (LabelClass) labels.get(key);
        if (result == null) {
            throw new NullPointerException("Label '" + key + "' not found");
        }
        return result;
    }

    public void addLabel(LabelClass lc) {
        labels.put(lc.getName(), lc);
    }

    public QueryClass getQuery(String key) {
        QueryClass result = (QueryClass) queries.get(key);
        if (result == null) {
            throw new NullPointerException("Query '" + key + "' not found");
        }
        return result;
    }

    public void addQuery(QueryClass qc) {
        queries.put(qc.getName(), qc);
    }

    public OrderClass getOrder(String key) {
        OrderClass result = (OrderClass) orders.get(key);
        if (result == null) {
            throw new NullPointerException("Order '" + key + "' not found");
        }
        return result;
    }

    public void addOrder(OrderClass oc) {
        orders.put(oc.getName(), oc);
    }

    public ViewClass getView(String key) {
        ViewClass result = (ViewClass) views.get(key);
        if (result == null) {
            throw new NullPointerException("View '" + key + "' not found");
        }
        return result;
    }
    
    public void findRoles(UserManager um) {
        roles = um.getAllRoles();
    }
    public void findPermissions(UserManager um) {
        rolePermissions = new ListMapClass();
        for (int i = 0; i < roles.size(); i++) {
            Role dm = (Role) roles.get(i);
            List dmPermList = um.getPermissionsByRoleId(dm.getId());
            for (int j = 0; j < dmPermList.size(); j++) {
                Permission dmPerm = (Permission) dmPermList.get(j);
                rolePermissions.addChild(dm.getId() + dmPerm.getModuleName(),
                                         dmPerm);
            }
        }
    }
    public void addView(ViewClass vc) {
        views.put(vc.getName(), vc);
    }

    public synchronized void config(String file,
                                    String winRarPath,
                                    String ftpPath,
                                    String attachPath,
                                    ServletContext sc) throws Exception {
        configByFile(file);
        configByDb(sc);
        this.realPath = sc.getRealPath("");
        this.startupTime = new Date();
    }

    private static void configByFile(String file) throws Exception {
        Digester digester = new Digester();
        digester.setNamespaceAware(true);
        digester.setValidating(false);
        digester.setUseContextClassLoader(true);
        digester.push(Config.getInstance());
        configOperators(digester);
        configLabels(digester);
        configQueries(digester);
        configOrders(digester);
        configViews(digester);
        digester.parse(file);
    }

    private void configByDb(ServletContext sc) throws Exception {
        ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(sc);
        configSubjects(ctx);
    }

    public void configSubjects(WebApplicationContext ctx) {
        LOG.info("Config Airlines...");
        BaseDao baseDao = (BaseDao) ctx.getBean("baseDao");
        List dmList = baseDao.getAllObjects(PickSubject.class);
        subjects = new ListMapClass();
        for (int i = 0; i < dmList.size(); i++) {
            PickSubject dm = (PickSubject) dmList.get(i);
            subjects.addChild(dm.getSubCode(), dm);
        }
        LOG.info("Config.size = " + dmList.size());
    }

    private static void configOperators(Digester digester) {
        LOG.info("Config Operator...");
        digester.addObjectCreate("config/operators/operator", "class",
                Operator.class);
        digester.addSetProperties("config/operators/operator");
        digester.addSetNext("config/operators/operator", "addOperator");
    }

    private static void configLabels(Digester digester) {
        LOG.info("Config Label...");
        digester.addObjectCreate("config/labels/label", LabelClass.class);

        digester.addSetProperties("config/labels/label");
        digester.addSetNext("config/labels/label", "addLabel");
    }

    private static void configQueries(Digester digester) {
        LOG.info("Config Query...");
        digester.addObjectCreate("config/queries/query", QueryClass.class);
        digester.addSetProperties("config/queries/query");
        digester.addObjectCreate("config/queries/query/dmproperty",
                DmProperty.class);
        digester.addSetProperties("config/queries/query/dmproperty");
        digester.addObjectCreate("config/queries/query/dmproperty/property",
                QueryProperty.class);
        digester.addSetProperties("config/queries/query/dmproperty/property");
        digester.addSetNext("config/queries/query/dmproperty/property",
                "addChild");
        digester.addSetNext("config/queries/query/dmproperty", "addChild");
        digester.addSetNext("config/queries/query", "addQuery");
    }

    private static void configOrders(Digester digester) {
        LOG.info("Config Order...");
        digester.addObjectCreate("config/orders/order", OrderClass.class);
        digester.addSetProperties("config/orders/order");
        digester.addObjectCreate("config/orders/order/property",
                OrderProperty.class);
        digester.addSetProperties("config/orders/order/property");
        digester.addSetNext("config/orders/order/property", "addChild");
        digester.addSetNext("config/orders/order", "addOrder");
    }

    private static void configViews(Digester digester) {
        LOG.info("Config View...");
        digester.addObjectCreate("config/views/view", ViewClass.class);
        digester.addSetProperties("config/views/view");
        digester.addObjectCreate("config/views/view/property",
                ViewProperty.class);
        digester.addSetProperties("config/views/view/property");
        digester.addSetNext("config/views/view/property", "addChild");
        digester.addSetNext("config/views/view", "addView");
    }

    public String getRealPath() {
        return realPath;
    }

    public Date getStartupTime() {
        return startupTime;
    }

    public Object getBean(String beanName) {
        return ctx.getBean(beanName);
    }

    public ListMapClass getSubjects() {
        return subjects;
    }

	public ListMapClass getRolePermissions() {
		return rolePermissions;
	}

	public void setRolePermissions(ListMapClass rolePermissions) {
		this.rolePermissions = rolePermissions;
	}

	public List getRoles() {
		return roles;
	}

	public void setRoles(List roles) {
		this.roles = roles;
	}
}
